<!DOCTYPE html>
<html lang="en">
    <head>
            <meta charset="utf-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            
            
            
            <link rel="shortcut icon" href="../../img/favicon.ico">
        
        <script type="text/javascript" src="//game.bmob.cn/static/doc_union.js"></script>
            <title>Bmob文档中心</title>
            <link href="../../css/bootstrap-custom.min.css" rel="stylesheet">
            <link href="../../css/font-awesome-4.5.0.css" rel="stylesheet">
            <link href="../../css/base.css" rel="stylesheet">
            <link rel="stylesheet" href="../../css/highlight.css">
            <link href="../../css/agate.css" rel="stylesheet">
            <link href="../../css/custom.css" rel="stylesheet" id="custom">
    </head>

    <body >

        <div class="navbar navbar-fixed-top" role="navigation">
    <div class="main-nav">
        <!-- Collapsed navigation -->
        <div class="navbar-header">
            <a class="navbar-brand" href="../..">
                <!--Bmob文档中心-->
                <img src="../../img/logo.png" alt="">
            </a>
        </div>

        <!-- Expanded navigation -->
        <div class="navbar-collapse collapse">

          <ul class="nav navbar-nav">
            
              <li class="pull-left">
                
					<a href="../..">文档首页</a>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="">数据服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">数据服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
								<li >
									<a href="../../data/android/">Android</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/ios/">iOS</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/csharp/">C#</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/php/">PHP</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/go/">GO</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/restful/">RESTful</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/javascript/">JavaScript</a>
                                </li>
                            
                            
                                <li >
                                    <a href="../../data/cocos2d_x/">Cocos2D-X</a>
                                </li>
							
                            
								<li >
									<a href="../../data/wechat_app/">小程序</a>
                                </li>
                            
                            
                                <li >
                                    <a href="../../data/wechat_app_new/">快应用</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../data/wechat_app_new/">Nodejs</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../data/wechat_app_new/">Cocos Creator</a>
                                </li>
							
                            
								<li >
									<a href="../../data/wechat_app_new/rm/">小程序(新)</a>
                                </li>
                            
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../cloud_function/android/">云函数</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">云函数 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../cloud_function/android/">Android</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/ios/">iOS</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/java/">Java</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/csharp/">C#</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/php/">PHP</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/javascript/">JavaScript</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/restful/">RESTful</a>
                                </li>
							
                            
								<li >
									<a href="../../cloud_function/web/">Web</a>
                                </li>
                            
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../sms/android/">短信服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">短信服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../sms/android/">Android</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/ios/">iOS</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/php/">PHP</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/javascript/">JavaScript</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/restful/">RESTful</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="">游戏实时后端</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">游戏实时后端 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
								<li >
									<a href="../../game/unity/quick_start/">Unity</a>
                                </li>
                            
                            
								<li >
									<a href="../../game/cocos_creator/quick_start/">Cocos Creator</a>
                                </li>
                            
                            
								<li >
									<a href="../../game/wechat_games/quick_start/">微信小游戏</a>
                                </li>
                            
                            
                                <li >
                                    <a href="../../game/cloud_function/develop_doc/">云函数</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../game/classic_case/">经典案例</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left active">
                
					<!--<a href="">IM服务</a>-->
					<li class="dropdown active">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">IM服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
								<li class="active">
									<a href="./">Android</a>
                                </li>
                            
                            
								<li >
									<a href="../ios/">iOS</a>
                                </li>
                            
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../push/android/">推送服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">推送服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../push/android/">Android</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/ios/">iOS</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/php/">PHP</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/javascript/">JavaScript</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/restful/">RESTful</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../other/common_problem/">其他</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">其他 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../other/common_problem/">常见问题</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../other/error_code/">错误码</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../other/data_safety/">数据安全</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../other/bql/">BQL</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li>
                  <a href="https://www.bmob.cn/repository/index" target="_blank">知识库</a>
              </li>
              <li>
                  <a href="http://doc.bmob.cn/video/index.html" target="_blank">视频教程</a>
              </li>
            </ul>
            
        </div>
    </div>
</div>

        <div class="pagebody" id="main-wrapper">
            <div class="sidebar">
                <div class="bs-sidebar hidden-print affix well" role="complementary">

	
		
	
		
				
				
				
				
				
				
				
				
				
				
				
				
				
		
	
		
				
				
				
				
				
				
				
				
		
	
		
				
				
				
				
				
		
	
		
				
				
				
				
				
		
	
		
				
					<div class="code-title">Android</div>
				
				
		
	
		
				
				
				
				
				
		
	
		
				
				
				
				
		
	


	<ul class="nav bs-sidenav">
		
			
		
			
		
			
		
			
		
			
		
			
				
					
						
							
								
									<li class="active">
										<a class="itm-l1" href="./">开发文档</a>
										
										<ul class="nav">
											
											<li class="active "><a href="#1bmobnewim-sdk">1、BmobNewIM SDK 介绍</a>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#11">1.1、特点描述</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#12">1.2、版本关系</a></li>
												</ul>
												
											</li>
												
											<li class=""><a href="#2bmobnewim-sdk">2、BmobNewIM SDK 集成</a>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#21">2.1、手动集成</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#22">2.2、自动集成</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#23">2.3、清单配置</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#24">2.4、代码配置</a></li>
												</ul>
												
											</li>
												
											<li class=""><a href="#3bmobnewim-sdk">3、BmobNewIM SDK 使用</a>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#31">3.1、案例流程图</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#32">3.2、用户管理</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#33">3.3、服务器连接</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#34">3.4、会话</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#35">3.5、消息</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#36">3.6、消息发送</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#37">3.7、自定义消息</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#38">3.8、消息接收</a></li>
												</ul>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#39">3.9、好友管理</a></li>
												</ul>
												
											</li>
												
											<li class=""><a href="#4bmobnewim-sdk">4、BmobNewIM SDK 混淆</a>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#41newim-sdk">4.1、NewIM SDK 混淆</a></li>
												</ul>
												
											</li>
												
											<li class=""><a href="#5bmoboldim-sdk">5、BmobOldIM SDK 回顾</a>
												
												<ul class="nav nav-l2">
													<li><a class="itm-l2" href="#51oldim-sdk">5.1、OldIM SDK 回顾</a></li>
												</ul>
												
											</li>
												
										</ul>
										
									</li>
								
									<li class="">
										<a class="itm-l1" href="class_doc/">类库文档</a>
										
									</li>
								
									<li class="">
										<a class="itm-l1" href="update_log/">更新日志</a>
										
									</li>
								
							
						
					
						
					
				
			
		
			
		
			
		
	</ul>
</div>
            </div>
            <div class="content" role="main">
                <div class="wrap">
                    

<h1 id="1bmobnewim-sdk">1、BmobNewIM SDK 介绍<a class="headerlink" href="#1bmobnewim-sdk" title="Permanent link">&para;</a></h1>
<p>Android BmobIM SDK v2.0.0开始的版本统称为<a href="https://github.com/chaozhouzhang/bmob-newim-demo">BmobNewIM SDK</a>，采用全新架构，设计更加合理规范，API更加简单易用，扩展性强。请确保您在使用BmobNewIM SDK之前已经了解此文档，如有疑问请加IM使用交流群<a href="">182897507</a>咨询。</p>
<h2 id="11">1.1、特点描述<a class="headerlink" href="#11" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>BmobNewIM SDK 特点</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>与用户系统解耦</td>
<td>终端用户聊天的唯一标识是objectId，不再受限于Bmob的用户系统</td>
</tr>
<tr>
<td>支持多账号登录、跨平台</td>
<td>支持单个设备多个账号登录，支持与iOS互通聊天</td>
</tr>
<tr>
<td>支持多种格式的富媒体消息</td>
<td>支持文本、图片、音频和地理位置等多种格式的富媒体消息</td>
</tr>
<tr>
<td>允许开发者自定义消息</td>
<td>支持开发者自定义消息类型，方便开发者扩展本业务逻辑</td>
</tr>
<tr>
<td>API设计更加合理规范</td>
<td>全新的架构设计，API更加简单易用，较BmobOldIM SDK 进一步降低开发者使用成本</td>
</tr>
</tbody>
</table>
<h2 id="12">1.2、版本关系<a class="headerlink" href="#12" title="Permanent link">&para;</a></h2>
<p>IM SDK 使用Data SDK的BmobFile用于图片、语音等文件消息的发送，因此必须导入特定版本的Data SDK。</p>
<table>
<thead>
<tr>
<th>IM SDK 版本</th>
<th>Data SDK 版本</th>
</tr>
</thead>
<tbody>
<tr>
<td>bmob-im:2.0.1 至 2.0.2</td>
<td>bmob-sdk:3.4.6-0304</td>
</tr>
<tr>
<td>bmob-im:2.0.3 至 2.0.4</td>
<td>bmob-sdk:3.4.6</td>
</tr>
<tr>
<td>bmob-im:2.0.5</td>
<td>bmob-sdk:3.4.7-aar</td>
</tr>
<tr>
<td>bmob-im:2.0.6 至 2.0.8</td>
<td>bmob-sdk:3.5.5</td>
</tr>
<tr>
<td>bmob-im:2.0.9</td>
<td>bmob-sdk:3.5.6</td>
</tr>
<tr>
<td>bmob-im:2.1.1</td>
<td>bmob-sdk:3.6.3</td>
</tr>
</tbody>
</table>
<h1 id="2bmobnewim-sdk">2、BmobNewIM SDK 集成<a class="headerlink" href="#2bmobnewim-sdk" title="Permanent link">&para;</a></h1>
<h2 id="21">2.1、手动集成<a class="headerlink" href="#21" title="Permanent link">&para;</a></h2>
<h3 id="211android-bmobnewim-sdkdemo">2.1.1、下载Android BmobNewIM SDK开发包及其Demo<a class="headerlink" href="#211android-bmobnewim-sdkdemo" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>下载平台</th>
<th>下载地址</th>
</tr>
</thead>
<tbody>
<tr>
<td>Github基于BmobNewIM SDK v2.1.1 的Demo</td>
<td><a href="https://github.com/chaozhouzhang/bmob-newim-demo">bmob-newim-demo</a></td>
</tr>
<tr>
<td>Bmob基于BmobNewIM SDK v2.0.9 的Demo</td>
<td><a href="http://www.bmob.cn/site/sdk#android_im_sdk_tab">bmob-newim-demo</a></td>
</tr>
<tr>
<td>Github基于BmobNewIM SDK v2.0.5 的Demo</td>
<td><a href="https://github.com/bodismile/bmob-newim-demo">bmob-newim-demo </a></td>
</tr>
</tbody>
</table>
<h3 id="212android-bmobnewim-sdk">2.1.2、解压Android BmobNewIM SDK开发包<a class="headerlink" href="#212android-bmobnewim-sdk" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>文件</th>
<th>使用</th>
</tr>
</thead>
<tbody>
<tr>
<td>libs</td>
<td>外部依赖库，拷贝于工程的libs文件夹下</td>
</tr>
<tr>
<td>NewIM_V2.x.x_Demo</td>
<td>开发示例，开发环境是Android Studio，功能是陌生人以及好友聊天</td>
</tr>
<tr>
<td>bmob_im_notification_strings.xml</td>
<td>消息通知的资源文件，拷贝于项目的values文件夹下</td>
</tr>
</tbody>
</table>
<h3 id="213appbuildgradlejnisync-now">2.1.3、在app下的build.gradle文件中设置jni依赖库的目录，设置后点击Sync Now同步配置<a class="headerlink" href="#213appbuildgradlejnisync-now" title="Permanent link">&para;</a></h3>
<pre><code class="gradle">android {
    sourceSets {
        main.jniLibs.srcDirs = ['libs']
   }
}
</code></pre>

<h2 id="22">2.2、自动集成<a class="headerlink" href="#22" title="Permanent link">&para;</a></h2>
<p>自IM SDK v2.0.5版本开始提供aar格式远程发布包，可以自动集成并结合Data SDK进行开发。</p>
<table>
<thead>
<tr>
<th>IM SDK aar格式所包含文件</th>
<th>Data SDK 版本</th>
</tr>
</thead>
<tbody>
<tr>
<td>BmobNewIM_(版本号)_(发布日期).jar</td>
<td>BmobNewIM的核心SDK</td>
</tr>
<tr>
<td>androidasync_2.1.6.jar</td>
<td>用于协议通讯</td>
</tr>
<tr>
<td>bmob_im_notification_strings.xml</td>
<td>用于消息通知</td>
</tr>
</tbody>
</table>
<h3 id="221projectbuildgradlebmobmaven">2.2.1、在Project下的build.gradle文件中添加Bmob的maven仓库地址<a class="headerlink" href="#221projectbuildgradlebmobmaven" title="Permanent link">&para;</a></h3>
<pre><code class="gradle">buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0'
    }
}

allprojects {
    repositories {
        jcenter()
        //TODO 集成：1.1、配置Bmob的maven仓库地址
        maven { url &quot;https://raw.github.com/bmob/bmob-android-sdk/master&quot; }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
</code></pre>

<h3 id="222appbuildgradledependenciessync-now">2.2.2、在app下的build.gradle文件中添加dependencies外部依赖库，添加后点击Sync Now同步配置<a class="headerlink" href="#222appbuildgradledependenciessync-now" title="Permanent link">&para;</a></h3>
<pre><code class="gradle">    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        //TODO 集成：1.2、配置IM SDK（bmob-im）版本和Data SDK（bmob-sdk）版本：特定版本的bmob-im依赖特定版本的bmob-sdk
        compile 'cn.bmob.android:bmob-im:2.1.1@aar'
        compile 'cn.bmob.android:bmob-sdk:3.6.3'
    }
</code></pre>

<h2 id="23">2.3、清单配置<a class="headerlink" href="#23" title="Permanent link">&para;</a></h2>
<h3 id="231-bmob_app_key">2.3.1、 添加Bmob_APP_KEY<a class="headerlink" href="#231-bmob_app_key" title="Permanent link">&para;</a></h3>
<pre><code class="xml">    &lt;!--TODO 集成：1.3、配置Bmob平台的应用密钥--&gt;
    &lt;meta-data
        android:name=&quot;Bmob_APP_KEY&quot;
        android:value=&quot;Bmob平台的Application ID&quot; /&gt;
</code></pre>

<h3 id="232">2.3.2、 添加权限<a class="headerlink" href="#232" title="Permanent link">&para;</a></h3>
<p>请注意在Android 6.0版本开始某些权限需要动态获取，详情请看Android Developwers官方文档，<a href="http://developer.android.com/intl/zh-cn/about/versions/marshmallow/android-6.0-changes.html">android-6.0-changes</a>和<a href="https://developer.android.google.cn/about/versions/nougat/android-7.0-changes.html">android-7.0-changes</a>。</p>
<pre><code class="xml">     &lt;!--TODO 1.4、配置IM SDK需要的权限--&gt;
    &lt;!--网络权限 --&gt;
    &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; /&gt;
    &lt;!-- 监听网络的变化 --&gt;
    &lt;uses-permission android:name=&quot;android.permission.ACCESS_NETWORK_STATE&quot; /&gt;
    &lt;uses-permission android:name=&quot;android.permission.CHANGE_NETWORK_STATE&quot; /&gt;
    &lt;!-- 设备休眠 --&gt;
    &lt;uses-permission android:name=&quot;android.permission.WAKE_LOCK&quot; /&gt;
    &lt;uses-permission android:name=&quot;android.permission.READ_PHONE_STATE&quot; /&gt;
    &lt;!-- sd卡存储--&gt;
    &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; /&gt;
    &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; /&gt;
    &lt;!--摄像头--&gt;
    &lt;uses-permission android:name=&quot;android.permission.CAMERA&quot; /&gt;
    &lt;!--录音--&gt;
    &lt;uses-permission android:name=&quot;android.permission.RECORD_AUDIO&quot; /&gt;
    &lt;!--通知震动--&gt;
    &lt;uses-permission android:name=&quot;android.permission.VIBRATE&quot; /&gt;

</code></pre>

<h3 id="233-servicereceiver">2.3.3、 添加service、receiver标签：<a class="headerlink" href="#233-servicereceiver" title="Permanent link">&para;</a></h3>
<pre><code class="xml">   &lt;!--TODO 集成：1.5、配置IM SDK需要的广播和服务--&gt;
  &lt;receiver android:name=&quot;cn.bmob.newim.core.ConnectChangeReceiver&quot; &gt;
        &lt;intent-filter&gt;
            &lt;action android:name=&quot;cn.bmob.action.RECONNECT&quot; /&gt;
            &lt;action android:name=&quot;android.net.conn.CONNECTIVITY_CHANGE&quot; /&gt;
            &lt;action android:name=&quot;android.intent.action.BOOT_COMPLETED&quot; /&gt;
            &lt;action android:name=&quot;android.intent.action.USER_PRESENT&quot; /&gt;
        &lt;/intent-filter&gt;
  &lt;/receiver&gt;
  &lt;service
    android:name=&quot;cn.bmob.newim.core.service.BmobIMService&quot;
    android:process=&quot;:bmobcore&quot; /&gt;
  &lt;service
    android:name=&quot;cn.bmob.newim.core.service.NotifyService&quot;
    android:process=&quot;:bmobcore&quot; /&gt;
  &lt;service android:name=&quot;cn.bmob.newim.core.service.ReConnectService&quot; /&gt;
  &lt;service android:name=&quot;cn.bmob.newim.core.service.HeartBeatService&quot; /&gt;
</code></pre>

<h2 id="24">2.4、代码配置<a class="headerlink" href="#24" title="Permanent link">&para;</a></h2>
<h3 id="241">2.4.1、自定义消息接收器<a class="headerlink" href="#241" title="Permanent link">&para;</a></h3>
<p>1、请自定义消息接收器继承自<code>BmobIMMessageHandler</code>来处理服务器发来的消息和离线消息。</p>
<pre><code class="java">//TODO 集成：1.6、自定义消息接收器处理在线消息和离线消息
public class DemoMessageHandler extends BmobIMMessageHandler{

    @Override
    public void onMessageReceive(final MessageEvent event) {
        //在线消息
    }

    @Override
    public void onOfflineReceive(final OfflineMessageEvent event) {
        //离线消息，每次connect的时候会查询离线消息，如果有，此方法会被调用
    }
}

</code></pre>

<h3 id="242bmobnewim-sdk">2.4.2、初始化BmobNewIM SDK<a class="headerlink" href="#242bmobnewim-sdk" title="Permanent link">&para;</a></h3>
<p>在Application的onCreate方法中调用<code>BmobIM.init(context)</code>，并注册自定义的<code>DemoMessageHandler</code>。</p>
<pre><code class="java">//TODO 集成：1.7、自定义Application，并在AndroidManifest.xml中配置
public class BmobIMApplication extends Application{

    @Override
    public void onCreate() {
        super.onCreate();
        //TODO 集成：1.8、初始化IM SDK，并注册消息接收器
        if (getApplicationInfo().packageName.equals(getMyProcessName())){
            BmobIM.init(this);
            BmobIM.registerDefaultMessageHandler(new DemoMessageHandler());
        }
    }

    /**
     * 获取当前运行的进程名
     * @return
     */
    public static String getMyProcessName() {
        try {
            File file = new File(&quot;/proc/&quot; + android.os.Process.myPid() + &quot;/&quot; + &quot;cmdline&quot;);
            BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
            String processName = mBufferedReader.readLine().trim();
            mBufferedReader.close();
            return processName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
</code></pre>

<ol>
<li>初始化方法包含了DataSDK的初始化步骤，故无需再初始化DataSDK。</li>
<li>最好判断只有主进程运行的时候才进行初始化，避免资源浪费。</li>
</ol>
<h1 id="3bmobnewim-sdk">3、BmobNewIM SDK 使用<a class="headerlink" href="#3bmobnewim-sdk" title="Permanent link">&para;</a></h1>
<h2 id="31">3.1、案例流程图<a class="headerlink" href="#31" title="Permanent link">&para;</a></h2>
<p><img alt="案例流程图" src="https://github.com/bmob/Bmob-Dev-docs/blob/master/im/Android/b_developdoc/image/IM.png?raw=true" /></p>
<h2 id="32">3.2、用户管理<a class="headerlink" href="#32" title="Permanent link">&para;</a></h2>
<p>BmobNewIM SDK只是即时通讯的消息收发渠道，本身并不提供用户系统，开发者可使用BmobSDK提供的用户管理方面功能，也可使用开发者自己的用户系统。</p>
<h3 id="321bmob">3.2.1、Bmob用户系统<a class="headerlink" href="#321bmob" title="Permanent link">&para;</a></h3>
<p>1、Demo使用的是Bmob的用户登录系统，一旦有用户注册就会在_User表中生成一条数据。对应流程图中的注册/登录和退出登录。</p>
<p>2、Demo中搜索用户其实就是模糊搜索_User表上的数据，然后用列表展示结果。对应流程图中的搜索用户。</p>
<p>3、Demo中用户信息页面其实就是查询_User表上某条数据的详细信息进行显示，包括objectid，username，avatar等，如果该用户不是自己，则显示成功后可以在用户信息页面进行添加好友和陌生人聊天操作。对应流程图中的个人信息、用户信息。</p>
<h3 id="322bmobimuserinfo">3.2.2、BmobIMUserInfo介绍<a class="headerlink" href="#322bmobimuserinfo" title="Permanent link">&para;</a></h3>
<p>BmobNewIM SDK内部会自动创建本地用户表<code>BmobIMUserInfo</code>，并对外提供查询、更新、删除等方法供开发者调用来操作本地用户表。</p>
<table>
<thead>
<tr>
<th>属性名</th>
<th>属性含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>本地数据库用户表的id值，开发者无需关心</td>
</tr>
<tr>
<td>userId</td>
<td>用户唯一id（Demo中用的是BmobUser的objectId）</td>
</tr>
<tr>
<td>name</td>
<td>用户名 （Demo中是用的是BmobUser的username）</td>
</tr>
<tr>
<td>avatar</td>
<td>用户头像（Demo中是用的是BmobUser的avatar）</td>
</tr>
</tbody>
</table>
<h3 id="323">3.2.3、更新本地用户信息<a class="headerlink" href="#323" title="Permanent link">&para;</a></h3>
<p>以下两种情况需要更新用户信息：
1. 当注册或登录成功并且成功连接到IM服务器后，需要更新下当前用户的信息到本地数据库的用户表中，这样才能通过getUserInfo方法获取到本地的用户信息。
2. 当接收到某人消息的时候，同样需要更新某人的用户信息到本地用户表中，否则在会话界面将默认显示的是用户的userId，也就是Demo中的BmobUser的objectId值。</p>
<h4 id="3231">3.2.3.1、更新单一本地用户信息<a class="headerlink" href="#3231" title="Permanent link">&para;</a></h4>
<pre><code>//TODO 用户管理：2.7、更新本地用户资料，用于在会话页面、聊天页面以及个人信息页面显示
BmobIM.getInstance().updateUserInfo(BmobIMUserInfo info)
</code></pre>

<h4 id="3232">3.2.3.2、批量更新本地用户信息<a class="headerlink" href="#3232" title="Permanent link">&para;</a></h4>
<pre><code>//TODO 用户管理：2.8、批量更新本地用户信息
BmobIM.getInstance().updateBatchUserInfo(List&lt;BmobIMUserInfo&gt; list)
</code></pre>

<h3 id="324">3.2.4、获取本地用户信息<a class="headerlink" href="#324" title="Permanent link">&para;</a></h3>
<p>BmobNewIM SDK内部会自动创建了一个本地数据库用来存储用户信息，开发者需要先调用<code>updateUserInfo</code>更新用户信息到本地数据库中，才能通过<code>getUserInfo(uid)</code>获取到本地用户信息。</p>
<pre><code>//TODO 用户管理：2.9、获取本地用户信息
BmobIM.getInstance().getUserInfo(String uid)
</code></pre>

<h2 id="33">3.3、服务器连接<a class="headerlink" href="#33" title="Permanent link">&para;</a></h2>
<h3 id="331">3.3.1、连接<a class="headerlink" href="#331" title="Permanent link">&para;</a></h3>
<p>登录成功、注册成功或处于登录状态重新打开应用后执行连接IM服务器的操作，调用<code>connect</code>方法，需要传入唯一用户标示<code>clientId</code>，Demo使用的是Bmob的用户登录系统<code>objectId</code>，。</p>
<pre><code class="java">        //TODO 连接：3.1、登录成功、注册成功或处于登录状态重新打开应用后执行连接IM服务器的操作
        User user = BmobUser.getCurrentUser(context,User.class);
        if (!TextUtils.isEmpty(user.getObjectId())) {
            BmobIM.connect(user.getObjectId(), new ConnectListener() {
                @Override
                public void done(String uid, BmobException e) {
                    if (e == null) {
                        //连接成功
                    } else {
                         //连接失败
                        toast(e.getMessage());
                    }
                }
            });
        }
</code></pre>

<h3 id="332">3.3.2、断开连接：<a class="headerlink" href="#332" title="Permanent link">&para;</a></h3>
<p>调用<code>disConnect</code>方法，客户端会断开与服务器之间的连接，再次聊天需要重新调用<code>connect</code>方法完成与服务器之间的连接。</p>
<pre><code class="java">//TODO 连接：3.2、退出登录需要断开与IM服务器的连接
BmobIM.getInstance().disConnect();
</code></pre>

<h3 id="333">3.3.3、监听服务器连接状态<a class="headerlink" href="#333" title="Permanent link">&para;</a></h3>
<p>调用<code>setOnConnectStatusChangeListener</code>方法即可监听到当前长链接的连接状态。</p>
<pre><code class="java">//TODO 连接：3.3、监听连接状态，可通过BmobIM.getInstance().getCurrentStatus()来获取当前的长连接状态
BmobIM.getInstance().setOnConnectStatusChangeListener(new ConnectStatusChangeListener() {
                @Override
                public void onChange(ConnectionStatus status) {
                    toast(status.getMsg());
                    Logger.i(BmobIM.getInstance().getCurrentStatus().getMsg());
                }
            });
</code></pre>

<h2 id="34">3.4、会话<a class="headerlink" href="#34" title="Permanent link">&para;</a></h2>
<h3 id="341">3.4.1、创建会话入口<a class="headerlink" href="#341" title="Permanent link">&para;</a></h3>
<p>BmobNewIM SDK 采用会话（<code>BmobIMConversation</code>）管理消息(<code>BmobIMMessage</code>)的方式，即消息的发送、查询和删除等操作均在指定会话下进行，因此需要先获取指定会话信息<code>BmobIMUserInfo</code>后创建会话入口<code>(BmobIMConversation)conversationEntrance</code>。创建会话入口成功后跳转到聊天页面，根据会话入口获取消息管理<code>(BmobIMConversation)messageManager</code>，而后使用消息管理在聊天页面进行消息的发送、查询和删除等操作。</p>
<h4 id="3411">3.4.1.1、创建暂态会话入口<a class="headerlink" href="#3411" title="Permanent link">&para;</a></h4>
<p>暂态会话不会被保存到本地数据库中，只提供消息发送功能，不提供查询，删除等功能。一般用于<code>自定义消息的发送</code>，比如添加好友的请求，在对方还没有同意的情况下，你并不希望在自己的会话列表中显示该会话。</p>
<pre><code class="java">//TODO 会话：4.1、创建一个暂态会话入口，发送添加好友请求，同意好友请求
BmobIMConversation conversationEntrance = BmobIM.getInstance().startPrivateConversation(info, true, null);
</code></pre>

<h4 id="3412">3.4.1.2、创建常态会话入口<a class="headerlink" href="#3412" title="Permanent link">&para;</a></h4>
<p>常态会话会被保存到本地数据库中，提供消息发送、查询，删除等功能。</p>
<pre><code class="java">//TODO 会话：4.1、创建一个常态会话入口，好友聊天，陌生人聊天
BmobIMConversation conversationEntrance = BmobIM.getInstance().startPrivateConversation(info, null);
</code></pre>

<h3 id="342">3.4.2、查询全部会话<a class="headerlink" href="#342" title="Permanent link">&para;</a></h3>
<pre><code>//TODO 会话：4.2、查询全部会话
BmobIM.getInstance().loadAllConversation()
</code></pre>

<h3 id="343">3.4.3、查询会话的未读消息数量<a class="headerlink" href="#343" title="Permanent link">&para;</a></h3>
<h4 id="3431">3.4.3.1、查询指定会话下的未读消息数量<a class="headerlink" href="#3431" title="Permanent link">&para;</a></h4>
<pre><code>//TODO 会话：4.3、查询指定会话下的未读消息数
BmobIM.getInstance().getUnReadCount(String conversationId)
</code></pre>

<h4 id="3432">3.4.3.2、查询全部会话的全部未读消息数<a class="headerlink" href="#3432" title="Permanent link">&para;</a></h4>
<pre><code>//TODO 会话：4.4、获取全部会话的未读消息数量
BmobIM.getInstance().getAllUnReadCount();
</code></pre>

<h3 id="344">3.4.4、删除指定会话<a class="headerlink" href="#344" title="Permanent link">&para;</a></h3>
<pre><code>//TODO 会话：4.5、删除会话，以下两种方式均可以删除会话
BmobIM.getInstance().deleteConversation(BmobIMConversation c);
BmobIM.getInstance().deleteConversation(String conversationId);
</code></pre>

<h3 id="345">3.4.5、清空全部会话<a class="headerlink" href="#345" title="Permanent link">&para;</a></h3>
<pre><code>//TODO 会话：4.6、清空全部会话，一般不会用到此方法
BmobIM.getInstance().clearAllConversation();
</code></pre>

<h3 id="346">3.4.6、更新会话<a class="headerlink" href="#346" title="Permanent link">&para;</a></h3>
<pre><code>//TODO 会话：4.7、更新会话资料-如果消息是暂态消息，则不更新会话资料

BmobIM.getInstance().updateConversation(conversation);
</code></pre>

<p>在与人私聊时，需要更新会话标题和会话图标及用户信息，可调用如下方法在<code>DemoMessageHandler</code>的全局消息接收器中进行统一更新。</p>
<pre><code class="java">    /**
     * 更新用户资料和会话资料
     *
     * @param event
     * @param listener
     */
    public void updateUserInfo(MessageEvent event, final UpdateCacheListener listener) {
        final BmobIMConversation conversation = event.getConversation();
        final BmobIMUserInfo info = event.getFromUserInfo();
        final BmobIMMessage msg = event.getMessage();
        String username = info.getName();
        String title = conversation.getConversationTitle();
        //SDK内部将新会话的会话标题用objectId表示，因此需要比对用户名和私聊会话标题，后续会根据会话类型进行判断
        if (!username.equals(title)) {
            UserModel.getInstance().queryUserInfo(info.getUserId(), new QueryUserListener() {
                @Override
                public void done(User s, BmobException e) {
                    if (e == null) {
                        String name = s.getUsername();
                        String avatar = s.getAvatar();
                        conversation.setConversationIcon(avatar);
                        conversation.setConversationTitle(name);
                        info.setName(name);
                        info.setAvatar(avatar);
                        //TODO 会话：2.7、更新用户资料，用于在会话页面、聊天页面以及个人信息页面显示
                        BmobIM.getInstance().updateUserInfo(info);
                        //TODO 会话：4.7、更新会话资料-如果消息是暂态消息，则不更新会话资料
                        if (!msg.isTransient()) {
                            BmobIM.getInstance().updateConversation(conversation);
                        }
                    } else {
                        Logger.e(e);
                    }
                    listener.done(null);
                }
            });
        } else {
            listener.done(null);
        }
    }
</code></pre>

<h2 id="35">3.5、消息<a class="headerlink" href="#35" title="Permanent link">&para;</a></h2>
<p>消息(<code>BmobIMMessage</code>)是所有消息的基类，其中<code>isTransient</code>属性来标识该条消息是否<code>自动保存到指定会话的本地数据库中</code>。</p>
<ul>
<li>设置为<code>true</code>，表明是暂态消息，那么这条消息<code>并不会自动保存到指定会话的本地消息数据库中</code>，SDK只负责发送和接收。</li>
<li>设置为<code>false</code>，表明不是暂态消息，那么这条消息<code>会自动保存到指定会话的本地消息数据库中</code>，并提供查询和删除操作。</li>
</ul>
<p>以下BmobNewIM SDK目前支持的消息类型。</p>
<table>
<thead>
<tr>
<th>消息类型</th>
<th>消息类名</th>
</tr>
</thead>
<tbody>
<tr>
<td>文本</td>
<td>BmobIMTextMessage</td>
</tr>
<tr>
<td>文件</td>
<td>BmobIMFileMessage</td>
</tr>
<tr>
<td>图像</td>
<td>BmobIMImageMessage</td>
</tr>
<tr>
<td>音频</td>
<td>BmobIMAudioMessage</td>
</tr>
<tr>
<td>视频</td>
<td>BmobIMVideoMessage</td>
</tr>
<tr>
<td>地理位置</td>
<td>BmobIMLocationMessage</td>
</tr>
</tbody>
</table>
<h3 id="351">3.5.1、获取消息管理<a class="headerlink" href="#351" title="Permanent link">&para;</a></h3>
<p>BmobNewIM SDK 采用会话（<code>BmobIMConversation</code>）管理消息(<code>BmobIMMessage</code>)的方式，即消息的发送、查询和删除等操作均在指定会话下进行，因此需要先获取指定会话信息<code>BmobIMUserInfo</code>后创建会话入口<code>(BmobIMConversation)conversationEntrance</code>。创建会话入口成功后跳转到聊天页面，根据会话入口获取消息管理<code>(BmobIMConversation)messageManager</code>，而后使用消息管理在聊天页面进行消息的发送、查询和删除等操作。</p>
<pre><code>//TODO 消息：5.1、根据会话入口获取消息管理，在聊天页面以及发送添加好友和同意添加好友请求时使用 
BmobIMConversation messageManager = BmobIMConversation.obtain(BmobIMClient.getInstance(), conversationEntrance);
</code></pre>

<h3 id="352">3.5.2、查询指定会话的聊天记录<a class="headerlink" href="#352" title="Permanent link">&para;</a></h3>
<pre><code class="java">//首次加载，可设置msg为null，下拉刷新的时候，可用消息表的第一个msg作为刷新的起始时间点，默认按照消息时间的降序排列
//TODO 消息：5.2、查询指定会话的消息记录
mConversationManager.queryMessages(msg, limit, new MessagesQueryListener() {
            @Override
            public void done(List&lt;BmobIMMessage&gt; list, BmobException e) {
                sw_refresh.setRefreshing(false);
                if (e == null) {
                    if (null != list &amp;&amp; list.size() &gt; 0) {
                        adapter.addMessages(list);
                        adapter.notifyDataSetChanged();
                        layoutManager.scrollToPositionWithOffset(list.size() - 1, 0);
                    }
                } else {
                    toast(e.getMessage() + &quot;(&quot; + e.getErrorCode() + &quot;)&quot;);
                }
            }
        });
</code></pre>

<h3 id="353">3.5.3、删除指定会话的聊天记录<a class="headerlink" href="#353" title="Permanent link">&para;</a></h3>
<pre><code class="java">//TODO 消息：5.3、删除指定聊天消息
mConversationManager.deleteMessage(BmobIMMessage msg)

//删除一条或多条聊天消息
mConversationManager.deleteBatchMessage(List&lt;BmobIMMessage&gt; msgs)

//清空该会话下的聊天消息，允许保留会话
mConversationManager.clearMessage(boolean isKeepConversion,MessageListener listener)
</code></pre>

<h3 id="354">3.5.4、更新指定会话的所有消息为已读状态<a class="headerlink" href="#354" title="Permanent link">&para;</a></h3>
<p>可以在聊天页面的<code>onDestory</code>方法中调用该方法<code>更新该会话的的所有消息为已读状态</code>：</p>
<pre><code>//TODO 消息：5.4、更新此会话的所有消息为已读状态
mConversationManager.updateLocalCache();
</code></pre>

<h2 id="36">3.6、消息发送<a class="headerlink" href="#36" title="Permanent link">&para;</a></h2>
<h3 id="361">3.6.1、文本消息<a class="headerlink" href="#361" title="Permanent link">&para;</a></h3>
<p>文本消息可以是纯文本，也可以是包含表情的文本消息，通过<code>BmobIMTextMessage</code>的<code>setContent</code>方法设置内容来构建<code>BmobIMTextMessage</code>实例，再调用消息管理<code>BmobIMConversation</code>的<code>sendMessage</code>方法发送。</p>
<pre><code class="java">    /**
     * 发送文本消息
     */
    private void sendMessage() {
        String text = edit_msg.getText().toString();
        if (TextUtils.isEmpty(text.trim())) {
            toast(&quot;请输入内容&quot;);
            return;
        }
        //TODO 发送消息：6.1、发送文本消息
        BmobIMTextMessage msg = new BmobIMTextMessage();
        msg.setContent(text);
        //可随意设置额外信息
        Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
        map.put(&quot;level&quot;, &quot;1&quot;);
        msg.setExtraMap(map);
        mConversationManager.sendMessage(msg, listener);
    }
</code></pre>

<h3 id="362">3.6.2、图片消息<a class="headerlink" href="#362" title="Permanent link">&para;</a></h3>
<p>图片可以是通过系统拍照或本地相册中获取的本地图片地址，也可以使用网络上某个有效的图片地址。</p>
<h4 id="3621">3.6.2.1、发送本地图片<a class="headerlink" href="#3621" title="Permanent link">&para;</a></h4>
<p>使用系统拍照功能或从本地相册中获取到本地图片地址(<code>localPath</code>)，然后调用构造方法<code>BmobIMImageMessage（String localPath）</code>来创建<code>BmobIMImageMessage</code>实例。</p>
<pre><code class="java">    /**
     * 发送本地图片文件
     */
    public void sendLocalImageMessage() {
        //TODO 发送消息：6.2、发送本地图片消息
        //正常情况下，需要调用系统的图库或拍照功能获取到图片的本地地址，开发者只需要将本地的文件地址传过去就可以发送文件类型的消息
        BmobIMImageMessage image = new BmobIMImageMessage(&quot;/storage/emulated/0/netease/cloudmusic/网易云音乐相册/小梦大半_1371091013186741.jpg&quot;);
        mConversationManager.sendMessage(image, listener);
    }
</code></pre>

<h4 id="3622url">3.6.2.2、发送远程图片URL<a class="headerlink" href="#3622url" title="Permanent link">&para;</a></h4>
<p>调用BmobIMImageMessage的<code>setRemoteUrl</code>方法设置远程图片URL来创建<code>BmobIMImageMessage</code>实例。</p>
<pre><code class="java">    /**
     * 直接发送远程图片地址
     */
    public void sendRemoteImageMessage() {
        //TODO 发送消息：6.3、发送远程图片消息
        BmobIMImageMessage image = new BmobIMImageMessage();
        image.setRemoteUrl(&quot;https://avatars3.githubusercontent.com/u/11643472?v=4&amp;u=df609c8370b3ef7a567457eafd113b3ba6ba3bb6&amp;s=400&quot;);
        mConversationManager.sendMessage(image, listener);
    }
</code></pre>

<h3 id="363">3.6.3、语音消息<a class="headerlink" href="#363" title="Permanent link">&para;</a></h3>
<p>语音可以是通过录制音频得到的本地音频地址，也可以使用网络上某个有效的音频地址。</p>
<h4 id="3631">3.6.3.1、发送本地音频文件：<a class="headerlink" href="#3631" title="Permanent link">&para;</a></h4>
<pre><code class="java">    /**
     * 发送本地音频文件
     */
    private void sendLocalAudioMessage() {
        BmobIMAudioMessage audio = new BmobIMAudioMessage(&quot;此处替换为你本地的音频文件地址&quot;);
        //TODO 发送消息：6.4、发送本地音频文件消息
        mConversationManager.sendMessage(audio, listener);
    }
</code></pre>

<h4 id="3632url">3.6.3.2、发送远程音频URL地址<a class="headerlink" href="#3632url" title="Permanent link">&para;</a></h4>
<pre><code class="java">    /**
     * 发送远程音频文件
     */
    private void sendRemoteAudioMessage(){
        //TODO 发送消息：6.5、发送本地音频文件消息
        BmobIMAudioMessage audio = new BmobIMAudioMessage();
        audio.setRemoteUrl(&quot;此处替换为你远程的音频文件地址&quot;);
        mConversationManager.sendMessage(audio, listener);
    }
</code></pre>

<h3 id="364">3.6.4、视频消息<a class="headerlink" href="#364" title="Permanent link">&para;</a></h3>
<p>视频可以是通过录制视频得到的本地视频地址，也可以使用网络上某个有效的视频地址。</p>
<h4 id="3641">3.6.4.1、发送本地视频文件：<a class="headerlink" href="#3641" title="Permanent link">&para;</a></h4>
<pre><code class="java">    /**
     * 发送本地视频文件
     */
    private void sendLocalVideoMessage() {
        BmobIMVideoMessage video = new BmobIMVideoMessage(&quot;此处替换为你本地的视频文件地址&quot;);
        //TODO 发送消息：6.6、发送本地视频文件消息
        mConversationManager.sendMessage(video, listener);
    }
</code></pre>

<h4 id="3642url">3.6.4.2、发送远程视频URL地址<a class="headerlink" href="#3642url" title="Permanent link">&para;</a></h4>
<pre><code class="java">    /**
     * 发送远程视频文件
     */
    private void sendRemoteVideoMessage(){
        //TODO 发送消息：6.7、发送本地音频文件消息
        BmobIMAudioMessage audio = new BmobIMAudioMessage();
        audio.setRemoteUrl(&quot;此处替换为你远程的音频文件地址&quot;);
        mConversationManager.sendMessage(audio, listener);
    }
</code></pre>

<h3 id="364_1">3.6.4、文件消息<a class="headerlink" href="#364_1" title="Permanent link">&para;</a></h3>
<p>文件可以是本地文件地址，也可以使用网络上某个有效的文件地址。
图片、音频、视频文件消息其实都是文件消息，本地文件的发送其实是SDK先把文件上传到服务器，再把文件服务器地址发送给接收方，接收方收到文件地址的消息后再进行下载和显示。而远程文件仅仅只是省去了文件上传这一步骤而已。</p>
<h4 id="3641_1">3.6.4.1、发送本地文件：<a class="headerlink" href="#3641_1" title="Permanent link">&para;</a></h4>
<pre><code class="java">   /**
     * 发送本地文件
     */
    public void sendLocalFileMessage() {
        //TODO 发送消息：6.8、发送本地文件消息
        BmobIMFileMessage file = new BmobIMFileMessage(&quot;此处替换为你本地的文件地址&quot;);
        mConversationManager.sendMessage(file, listener);
    }
</code></pre>

<h4 id="3642url_1">3.6.4.2、发送远程文件URL地址<a class="headerlink" href="#3642url_1" title="Permanent link">&para;</a></h4>
<pre><code class="java">    /**
     * 发送远程文件
     */
    public void sendRemoteFileMessage() {
        //TODO 发送消息：6.9、发送远程文件消息
        BmobIMFileMessage file = new BmobIMFileMessage();
        file.setRemoteUrl(&quot;此处替换为你远程的文件地址&quot;);
        mConversationManager.sendMessage(file, listener);
    }
</code></pre>

<h3 id="365">3.6.5、地理位置消息<a class="headerlink" href="#365" title="Permanent link">&para;</a></h3>
<p>地理位置可以通过任意地图SDK获取到经纬度，详细地址等信息，然后调用<code>BmobIMLocationMessage(String address,double latitude,double longitude)</code>构造方法构建<code>BmobIMLocationMessage</code>实例，再调用<code>BmobIMConversation</code>的<code>sendMessage</code>方法发送。：</p>
<pre><code class="java">    /**
     * 发送地理位置消息
     */
    public void sendLocationMessage() {
        //TODO 发送消息：6.10、发送位置消息
        //测试数据，真实数据需要从地图SDK中获取
        BmobIMLocationMessage location = new BmobIMLocationMessage(&quot;广州番禺区&quot;, 23.5, 112.0);
        Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
        map.put(&quot;from&quot;, &quot;百度地图&quot;);
        location.setExtraMap(map);
        mConversationManager.sendMessage(location, listener);
    }
</code></pre>

<h2 id="37">3.7、自定义消息<a class="headerlink" href="#37" title="Permanent link">&para;</a></h2>
<h3 id="371">3.7.1、设置额外信息<a class="headerlink" href="#371" title="Permanent link">&para;</a></h3>
<p>有些时候，开发者需要在发送消息时携带一些额外信息，例如<code>发送方的设备类型、图片的拍摄地点或者音频的来源</code>等，那么开发者可以通过 <code>BmobIMExtraMessage.extraMap</code>属性来解决，任何继承<code>BmobIMExtraMessage</code>类的消息均支持设置额外信息。</p>
<pre><code>    BmobIMAudioMessage audio =new BmobIMAudioMessage();
    image.setRemoteUrl(&quot;远程音频地址&quot;);
    //设置音频文件的来源
    Map&lt;String,Object&gt; map =new HashMap&lt;&gt;();
    map.put(&quot;from&quot;, &quot;优酷&quot;);
    //TODO 自定义消息：7.1、给消息设置额外信息
    audio.setExtraMap(map);
    mConversationManager.sendMessage(audio, listener);
</code></pre>

<h3 id="372">3.7.2、自定义消息类型<a class="headerlink" href="#372" title="Permanent link">&para;</a></h3>
<p>如果设置额外信息无法满足开发者的需求，那么开发者也可以自定义自己的消息类型。
1. 继承自<code>BmobIMExtraMessage</code>类；
2. 重写<code>getMsgType</code>方法，填写自定义的消息类型；
3. 重写<code>isTransient</code>方法，定义是否是暂态消息。</p>
<pre><code>  //TODO 自定义消息：7.2、自定义消息类型，用于发送添加好友请求
    public class AddFriendMessage extends BmobIMExtraMessage{

        @Override
        public String getMsgType() {
            return &quot;add&quot;;
        }

        @Override
        public boolean isTransient() {
            return true;
        }

        public AddFriendMessage(){}

    }
</code></pre>

<h2 id="38">3.8、消息接收<a class="headerlink" href="#38" title="Permanent link">&para;</a></h2>
<h3 id="381">3.8.1、自定义消息接收器<a class="headerlink" href="#381" title="Permanent link">&para;</a></h3>
<h4 id="3811bmobimmessagehandler">3.8.1.1、自定义消息接收器继承自<code>BmobIMMessageHandler</code>来处理服务器发来的消息和离线消息。<a class="headerlink" href="#3811bmobimmessagehandler" title="Permanent link">&para;</a></h4>
<pre><code class="java">//TODO 消息接收：8.1、自定义全局消息接收器
public class DemoMessageHandler extends BmobIMMessageHandler{

    private Context context;
    public DemoMessageHandler(Context context) {
        this.context = context;
    }

    @Override
    public void onMessageReceive(final MessageEvent event) {
        //接收处理在线消息
    }

    @Override
    public void onOfflineReceive(final OfflineMessageEvent event) {
        //接收处理离线消息，每次调用connect方法时会查询一次离线消息，如果有，此方法会被调用
    }
}

</code></pre>

<h4 id="3812">3.8.1.2、单个页面的自定义接收器<a class="headerlink" href="#3812" title="Permanent link">&para;</a></h4>
<p>使用IM SDK不仅可以使用<code>BmobIMMessageHandler</code>方式来注册全局的消息接收器，还可以使用<code>MessageListHandler</code>为单个页面注册消息接收器，具体步骤如下：</p>
<ol>
<li>在<code>Activity/Fragment</code>中实现<code>MessageListHandler</code>接口；</li>
<li>在<code>onResume</code>方法中添加页面消息监听器：<code>BmobIM.getInstance().addMessageListHandler(this)</code>；</li>
<li>在<code>onPause</code>方法中移除页面消息监听器：<code>BmobIM.getInstance().removeMessageListHandler(this)</code>；</li>
<li>在<code>MessageListHandler</code>接口的<code>onMessageReceive</code>方法中做相关的操作。</li>
</ol>
<p>具体示例可查看NewIMDemo中的<code>ChatActivity</code>类：</p>
<pre><code class="java">//TODO 消息接收：8.2、单个页面的自定义接收器
@Override
public void onMessageReceive(List&lt;MessageEvent&gt; list) {
    //接收处理在线、离线消息
}

</code></pre>

<h3 id="382">3.8.2、应用内消息接收<a class="headerlink" href="#382" title="Permanent link">&para;</a></h3>
<p>SDK内部使用EventBus来进行应用内消息的分发，故在应用内需要接收消息的地方注册和解注册EventBus即可，不过SDK并没有集成EventBus，开发者需要在自己的项目中另外集成EventBus。</p>
<p>SDK内部有两种EventBus事件：<code>MessageEvent（在线消息）</code>、<code>OfflineMessageEvent(离线消息)</code>。</p>
<p>1、注册EventBus</p>
<pre><code>EventBus.getDefault().register(this);

</code></pre>

<p>2、注销EventBus</p>
<pre><code class="java">EventBus.getDefault().unregister(this);

</code></pre>

<p>3、处理在线消息</p>
<pre><code class="java">/**聊天消息接收事件
 * @param event
 */
//TODO 消息接收：8.3、通知有在线消息接收
@Subscribe
public void onEventMainThread(MessageEvent event){
    //处理聊天消息
}

</code></pre>

<p>4、处理离线消息</p>
<pre><code class="java">
/**离线消息接收事件
 * @param event
 */
//TODO 消息接收：8.4、通知有离线消息接收
@Subscribe
public void onEventMainThread(OfflineMessageEvent event){
    //处理离线消息
}

</code></pre>

<h3 id="383">3.8.3、应用外通知栏提醒<a class="headerlink" href="#383" title="Permanent link">&para;</a></h3>
<p><code>BmobNotificationManager</code>类提供展示通知栏的方法，你也可以使用自己的展示通知栏方法。</p>
<p>1、多个用户的多条消息合并成一条通知：有XX个联系人发来了XX条消息。</p>
<pre><code class="java">/**显示通知：多个用户的多条消息合并显示一条通知
 * @param event 某个消息事件：包含消息、会话及发送用户的信息
 * @param intent 跳转intent
 */
 //TODO 消息接收：8.5、多个用户的多条消息合并成一条通知：有XX个联系人发来了XX条消息
 BmobNotificationManager.getInstance(context).showNotification(MessageEvent event,Intent pendingIntent);
</code></pre>

<p>2、自定义通知消息：始终只有一条通知，新消息覆盖旧消息。</p>
<pre><code class="java"> /**显示通知
 * @param largerIcon 通知栏图标 开发者可传应用图标，也可以将聊天头像转成bitmap
 * @param title 标题
 * @param content 内容
 * @param ticker 状态栏上显示的内容
 * @param intent 跳转的intent
 */
 //TODO 消息接收：8.6、自定义通知消息：始终只有一条通知，新消息覆盖旧消息
BmobNotificationManager.getInstance(context).showNotification(Bitmap largerIcon,String title, String content, String ticker,Intent intent);
</code></pre>

<h2 id="39">3.9、好友管理<a class="headerlink" href="#39" title="Permanent link">&para;</a></h2>
<p>BmobNewIM SDK中并没有集成好友管理相关的功能，为了方便开发者建立基于好友之间的聊天模式，在Demo中使用Data SDK新建了<code>Friend</code>表来进行好友管理。</p>
<pre><code class="java">/**好友表
 * @author smile
 * @project Friend
 * @date 2016-04-26
 */
//TODO 好友管理：9.1、创建好友表
public class Friend extends BmobObject{
     //用户
    private User user;
     //好友
    private User friendUser;
    //getter setter...
}
</code></pre>

<p>在控制台建表的时候请设置唯一键为user和friendUser唯一，以防出现多次发送请求消息重复添加相同用户为好友的情况。</p>
<p><img alt="设置Friend表唯一键" src="https://github.com/bmob/Bmob-Dev-docs/blob/master/im/Android/b_developdoc/image/Friend.png?raw=true" /></p>
<h3 id="391">3.9.1、获取好友列表<a class="headerlink" href="#391" title="Permanent link">&para;</a></h3>
<pre><code class="java">/**
 * 查询好友
 * @param listener
 */
//TODO 好友管理：9.2、查询好友
public void queryFriends(final FindListener&lt;Friend&gt; listener){
    BmobQuery&lt;Friend&gt; query = new BmobQuery&lt;&gt;();
    User user =BmobUser.getCurrentUser(getContext(), User.class);
    query.addWhereEqualTo(&quot;user&quot;, user);
    query.include(&quot;friendUser&quot;);
    query.order(&quot;-updatedAt&quot;);
    query.findObjects(getContext(), new FindListener&lt;Friend&gt;() {
        @Override
        public void onSuccess(List&lt;Friend&gt; list) {
            if (list != null &amp;&amp; list.size() &gt; 0) {
                listener.onSuccess(list);
            } else {
                listener.onError(0, &quot;暂无联系人&quot;);
            }
        }

        @Override
        public void onError(int i, String s) {
            listener.onError(i, s);
        }
    });
}
</code></pre>

<h3 id="392">3.9.2、删除好友<a class="headerlink" href="#392" title="Permanent link">&para;</a></h3>
<pre><code class="java">/**
 * 删除好友
 * @param f
 * @param listener
 */
//TODO 好友管理：9.3、删除好友
public void deleteFriend(Friend f,DeleteListener listener){
    Friend friend =new Friend();
    friend.delete(getContext(),f.getObjectId(),listener);
}
</code></pre>

<h3 id="393">3.9.3、添加好友<a class="headerlink" href="#393" title="Permanent link">&para;</a></h3>
<h4 id="3931">3.9.3.1、本地数据库存储添加好友请求<a class="headerlink" href="#3931" title="Permanent link">&para;</a></h4>
<p>Demo中创建了一个<code>NewFriend</code>的本地数据库类用来存储所有的添加好友请求。</p>
<pre><code class="java">/**本地的好友请求表
 * @author :smile
 * @project:NewFriend
 * @date :2016-04-26-17:28
 */
//TODO 好友管理：9.4、本地数据库存储添加好友的请求
public class NewFriend implements java.io.Serializable {

    private Long id;
    //用户uid
    private String uid;
    //留言消息
    private String msg;
    //用户名
    private String name;
    //头像
    private String avatar;
    //状态：未读、已读、已添加、已拒绝等
    private Integer status;
    //请求时间
    private Long time;

    //getter setter...
}

</code></pre>

<h4 id="3932">3.9.3.2、自定义添加好友的消息类型<a class="headerlink" href="#3932" title="Permanent link">&para;</a></h4>
<p>Demo中创建了一个<code>AddFriendMessage</code>类来展示如何发送自定义的添加好友请求的消息。</p>
<pre><code class="java">/**添加好友请求-自定义消息类型
 * @author :smile
 * @project:AddFriendMessage
 * @date :2016-01-30-17:28
 */
//TODO 好友管理：9.5、自定义添加好友的消息类型
public class AddFriendMessage extends BmobIMExtraMessage{

    public AddFriendMessage(){}

    @Override
    public String getMsgType() {
          //自定义一个`add`的消息类型
        return &quot;add&quot;;
    }

    @Override
    public boolean isTransient() {
        //设置为true,表明为暂态消息，那么这条消息并不会保存到本地db中，SDK只负责发送出去
        return true;
    }

    ...

}

</code></pre>

<h4 id="3933">3.9.3.3、自定义同意添加好友的消息类型<a class="headerlink" href="#3933" title="Permanent link">&para;</a></h4>
<p>Demo中创建了一个<code>AgreeAddFriendMessage</code>类来展示如何发送自定义的同意添加好友请求的消息，并在对方的本地会话表中新增消息类型。</p>
<pre><code class="java">/**同意添加好友请求-仅仅只用于发送同意添加好友的消息
 * @author smile
 * @project AgreeAddFriendMessage
 * @date 2016-03-04-10:41
 */
//TODO 好友管理：9.6、自定义同意添加好友的消息类型
public class AgreeAddFriendMessage extends BmobIMExtraMessage{

    //以下均是从extra里面抽离出来的字段，方便获取
    private String uid;//最初的发送方
    private Long time;
    private String msg;//用于通知栏显示的内容

    @Override
    public String getMsgType() {
        //自定义一个`agree`的消息类型
        return &quot;agree&quot;;
    }

    @Override
    public boolean isTransient() {
        //此处将同意添加好友的请求设置为false，为了演示怎样向会话表和消息表中新增一个类型，在对方的会话列表中增加`我通过了你的好友验证请求，我们可以开始聊天了!`这样的类型
        return false;
    }

    //getter setter...

    ...
}

</code></pre>

<h3 id="384">3.8.4、发送添加好友的请求<a class="headerlink" href="#384" title="Permanent link">&para;</a></h3>
<pre><code class="java">    /**
     * 发送添加好友的请求
     */
    //TODO 好友管理：9.7、发送添加好友请求
    private void sendAddFriendMessage() {
        //TODO 会话：4.1、创建一个暂态会话入口，发送好友请求
        BmobIMConversation conversationEntrance = BmobIM.getInstance().startPrivateConversation(info, true, null);
        //TODO 消息：5.1、根据会话入口获取消息管理，发送好友请求
        BmobIMConversation messageManager = BmobIMConversation.obtain(BmobIMClient.getInstance(), conversationEntrance);
        AddFriendMessage msg = new AddFriendMessage();
        User currentUser = BmobUser.getCurrentUser(User.class);
        msg.setContent(&quot;很高兴认识你，可以加个好友吗?&quot;);//给对方的一个留言信息
        //TODO 这里只是举个例子，其实可以不需要传发送者的信息过去
        Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
        map.put(&quot;name&quot;, currentUser.getUsername());//发送者姓名
        map.put(&quot;avatar&quot;, currentUser.getAvatar());//发送者的头像
        map.put(&quot;uid&quot;, currentUser.getObjectId());//发送者的uid
        msg.setExtraMap(map);
        messageManager.sendMessage(msg, new MessageSendListener() {
            @Override
            public void done(BmobIMMessage msg, BmobException e) {
                if (e == null) {//发送成功
                    toast(&quot;好友请求发送成功，等待验证&quot;);
                } else {//发送失败
                    toast(&quot;发送失败:&quot; + e.getMessage());
                }
            }
        });
    }
</code></pre>

<h3 id="385">3.8.5、发送同意添加好友的请求<a class="headerlink" href="#385" title="Permanent link">&para;</a></h3>
<p>以下摘自<code>NewFriendHolder(cn.bmob.imdemo.adapter)</code>类：</p>
<pre><code class="java">    /**
     * 发送同意添加好友的消息
     */
    //TODO 好友管理：9.8、发送同意添加好友
    private void sendAgreeAddFriendMessage(final NewFriend add, final SaveListener&lt;Object&gt; listener) {
        BmobIMUserInfo info = new BmobIMUserInfo(add.getUid(), add.getName(), add.getAvatar());
        //TODO 会话：4.1、创建一个暂态会话入口，发送同意好友请求
        BmobIMConversation conversationEntrance = BmobIM.getInstance().startPrivateConversation(info, true, null);
        //TODO 消息：5.1、根据会话入口获取消息管理，发送同意好友请求
        BmobIMConversation messageManager = BmobIMConversation.obtain(BmobIMClient.getInstance(), conversationEntrance);
        //而AgreeAddFriendMessage的isTransient设置为false，表明我希望在对方的会话数据库中保存该类型的消息
        AgreeAddFriendMessage msg = new AgreeAddFriendMessage();
        final User currentUser = BmobUser.getCurrentUser(User.class);
        msg.setContent(&quot;我通过了你的好友验证请求，我们可以开始 聊天了!&quot;);//这句话是直接存储到对方的消息表中的
        Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
        map.put(&quot;msg&quot;, currentUser.getUsername() + &quot;同意添加你为好友&quot;);//显示在通知栏上面的内容
        map.put(&quot;uid&quot;, add.getUid());//发送者的uid-方便请求添加的发送方找到该条添加好友的请求
        map.put(&quot;time&quot;, add.getTime());//添加好友的请求时间
        msg.setExtraMap(map);
        messageManager.sendMessage(msg, new MessageSendListener() {
            @Override
            public void done(BmobIMMessage msg, BmobException e) {
                if (e == null) {//发送成功
                    //TODO 3、修改本地的好友请求记录
                    NewFriendManager.getInstance(context).updateNewFriend(add, Config.STATUS_VERIFIED);
                    listener.done(msg, e);
                } else {//发送失败
                    Logger.e(e.getMessage());
                    listener.done(msg, e);
                }
            }
        });
    }
</code></pre>

<h3 id="386">3.8.6、接收并处理好友相关的请求<a class="headerlink" href="#386" title="Permanent link">&para;</a></h3>
<pre><code class="java">    /**
     * 处理自定义消息类型
     *
     * @param msg
     */
    //TODO 好友管理：9.9、接收并处理好友相关的请求
    private void processCustomMessage(BmobIMMessage msg, BmobIMUserInfo info) {
        //消息类型
        String type = msg.getMsgType();
        //发送页面刷新的广播
        EventBus.getDefault().post(new RefreshEvent());
        //处理消息
        if (type.equals(AddFriendMessage.ADD)) {//接收到的添加好友的请求
            NewFriend friend = AddFriendMessage.convert(msg);
            //本地好友请求表做下校验，本地没有的才允许显示通知栏--有可能离线消息会有些重复
            long id = NewFriendManager.getInstance(context).insertOrUpdateNewFriend(friend);
            if (id &gt; 0) {
                showAddNotify(friend);
            }
        } else if (type.equals(AgreeAddFriendMessage.AGREE)) {//接收到的对方同意添加自己为好友,此时需要做的事情：1、添加对方为好友，2、显示通知
            AgreeAddFriendMessage agree = AgreeAddFriendMessage.convert(msg);
            addFriend(agree.getFromId());//添加消息的发送方为好友
            //这里应该也需要做下校验--来检测下是否已经同意过该好友请求，我这里省略了
            showAgreeNotify(info, agree);
        } else {
            Toast.makeText(context, &quot;接收到的自定义消息：&quot; + msg.getMsgType() + &quot;,&quot; + msg.getContent() + &quot;,&quot; + msg.getExtra(), Toast.LENGTH_SHORT).show();
        }
    }
</code></pre>

<h3 id="387friend">3.8.7、添加到Friend表中<a class="headerlink" href="#387friend" title="Permanent link">&para;</a></h3>
<p>在同意对方和收到对方同意的时候，需要添加好友关系到Friend表中。</p>
<h4 id="3871">3.8.7.1、同意对方的添加好友请求，添加对方为好友发送同意<a class="headerlink" href="#3871" title="Permanent link">&para;</a></h4>
<pre><code class="java">    /**
     * TODO 好友管理：9.10、添加到好友表中再发送同意添加好友的消息
     *
     * @param add
     * @param listener
     */
    private void agreeAdd(final NewFriend add, final SaveListener&lt;Object&gt; listener) {
        User user = new User();
        user.setObjectId(add.getUid());
        UserModel.getInstance()
                .agreeAddFriend(user, new SaveListener&lt;String&gt;() {
                    @Override
                    public void done(String s, BmobException e) {
                        if (e == null) {
                            //TODO 2、发送同意添加好友的消息
                            sendAgreeAddFriendMessage(add, listener);
                        } else {
                            Logger.e(e.getMessage());
                            listener.done(null, e);
                        }
                    }
                });
    }
</code></pre>

<h4 id="3872">3.8.7.2、收到对方的同意添加好友请求后，添加对方为好友<a class="headerlink" href="#3872" title="Permanent link">&para;</a></h4>
<pre><code class="java">   /**
     * TODO 好友管理：9.11、收到同意添加好友后添加好友
     *
     * @param uid
     */
    private void addFriend(String uid) {
        User user = new User();
        user.setObjectId(uid);
        UserModel.getInstance()
                .agreeAddFriend(user, new SaveListener&lt;String&gt;() {
                    @Override
                    public void done(String s, BmobException e) {
                        if (e == null) {
                            Logger.e(&quot;success&quot;);
                        } else {
                            Logger.e(e.getMessage());
                        }
                    }
                });
    }
</code></pre>

<h1 id="4bmobnewim-sdk">4、BmobNewIM SDK 混淆<a class="headerlink" href="#4bmobnewim-sdk" title="Permanent link">&para;</a></h1>
<h2 id="41newim-sdk">4.1、NewIM SDK 混淆<a class="headerlink" href="#41newim-sdk" title="Permanent link">&para;</a></h2>
<pre><code>
# 不混淆im sdk
-keep class cn.bmob.newim.**{*;}
-dontwarn cn.bmob.newim.**
# 不混淆greenDao类
-dontwarn de.greenrobot.dao.**
-keep class de.greenrobot.dao.** { *;}
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
    public static java.lang.String TABLENAME;
}
-keep class **$Properties
# 不混淆async
-dontwarn com.koushikdutta.async.**
-keep class com.koushikdutta.async.** { *;}
</code></pre>

<h1 id="5bmoboldim-sdk">5、BmobOldIM SDK 回顾<a class="headerlink" href="#5bmoboldim-sdk" title="Permanent link">&para;</a></h1>
<h2 id="51oldim-sdk">5.1、OldIM SDK 回顾<a class="headerlink" href="#51oldim-sdk" title="Permanent link">&para;</a></h2>
<p>Android BmobIM SDK v2.0.0之前的版本统称为<a href="https://github.com/bmob/bmob-android-im-sdk">BmobOldIM SDK</a> ，BmobOldIM SDK已经开源但不再进行维护，请开发者集成Android BmobNewIM SDK进行开发。</p>
<table>
<thead>
<tr>
<th>BmobOldIM SDK 问题</th>
</tr>
</thead>
<tbody>
<tr>
<td>无法自定义消息类型</td>
</tr>
<tr>
<td>消息发送受限于BmobPushSDK</td>
</tr>
<tr>
<td>API设计不够合理规范且不易扩展</td>
</tr>
<tr>
<td>聊天消息出现接收延迟或丢失</td>
</tr>
</tbody>
</table>
                </div>
            </div>
        </div>

        
            <script>var base_url = '../..';</script>
            <script src="../../js/jquery-1.10.2.min.js"></script>
            <script src="../../js/bootstrap-3.0.3.min.js"></script>
            <script src="../../js/highlight.pack.js"></script>
            <script src="../../js/main.js"></script>
            <script src="../../js/base.js"></script>

        <div id="go-top"><i class="fa fa-chevron-up"></i></div>
        <a href="https://docs.bmob.cn/data/Android/a_faststart/doc/index.html" id="back" target="_blank">返回 <br> 旧版</a>
    </body>

</html>